Skip to main content

Section II Q-2: Canvas and Paint / Private Preferences (5 Marks)

Question

a) Explain the concept of Canvas and Paint in Android and their usage.

OR

b) How do you create and work with private preferences in Android?


Answer A: Canvas and Paint in Android

Concept of Canvas and Paint

Canvas and Paint are fundamental classes in Android for custom drawing and graphics rendering.

Canvas

  • Definition: A 2D drawing surface that provides methods to draw on a bitmap or view
  • Purpose: Acts as the drawing board where you can draw shapes, text, images, and paths
  • Scope: Handles the "where" and "how" of drawing operations

Paint

  • Definition: Holds style and color information for drawing operations
  • Purpose: Defines the appearance of drawn elements (color, stroke, fill, etc.)
  • Scope: Handles the "what it looks like" aspect of drawing

Key Features and Properties

Canvas Methods

MethodDescriptionExample
drawRect()Draw rectanglecanvas.drawRect(0, 0, 100, 100, paint)
drawCircle()Draw circlecanvas.drawCircle(50, 50, 25, paint)
drawLine()Draw linecanvas.drawLine(0, 0, 100, 100, paint)
drawText()Draw textcanvas.drawText("Hello", 10, 50, paint)
drawBitmap()Draw imagecanvas.drawBitmap(bitmap, 0, 0, paint)
drawPath()Draw custom pathcanvas.drawPath(path, paint)

Paint Properties

PropertyDescriptionUsage
ColorSet drawing colorpaint.setColor(Color.RED)
StyleFill or strokepaint.setStyle(Paint.Style.FILL)
Stroke WidthLine thicknesspaint.setStrokeWidth(5)
Text SizeFont sizepaint.setTextSize(24)
Anti-aliasSmooth edgespaint.setAntiAlias(true)

Complete Implementation Example

Custom View Class

package com.example.canvaspaintdemo;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View;

public class CustomDrawingView extends View {
private Paint redPaint, bluePaint, greenPaint, textPaint;
private Path customPath;

public CustomDrawingView(Context context) {
super(context);
initPaints();
}

public CustomDrawingView(Context context, AttributeSet attrs) {
super(context, attrs);
initPaints();
}

private void initPaints() {
// Red paint for filled shapes
redPaint = new Paint();
redPaint.setColor(Color.RED);
redPaint.setStyle(Paint.Style.FILL);
redPaint.setAntiAlias(true);

// Blue paint for strokes
bluePaint = new Paint();
bluePaint.setColor(Color.BLUE);
bluePaint.setStyle(Paint.Style.STROKE);
bluePaint.setStrokeWidth(8);
bluePaint.setAntiAlias(true);

// Green paint for gradients
greenPaint = new Paint();
greenPaint.setColor(Color.GREEN);
greenPaint.setStyle(Paint.Style.FILL);
greenPaint.setAlpha(150); // Semi-transparent
greenPaint.setAntiAlias(true);

// Text paint
textPaint = new Paint();
textPaint.setColor(Color.BLACK);
textPaint.setTextSize(48);
textPaint.setAntiAlias(true);
textPaint.setTextAlign(Paint.Align.CENTER);

// Create custom path
customPath = new Path();
customPath.moveTo(100, 400);
customPath.lineTo(200, 300);
customPath.lineTo(300, 400);
customPath.lineTo(250, 450);
customPath.lineTo(150, 450);
customPath.close();
}

@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);

// Set background
canvas.drawColor(Color.WHITE);

// Draw filled rectangle
canvas.drawRect(50, 50, 250, 150, redPaint);

// Draw stroked circle
canvas.drawCircle(400, 100, 75, bluePaint);

// Draw filled circle with transparency
canvas.drawCircle(400, 100, 50, greenPaint);

// Draw lines
canvas.drawLine(50, 200, 250, 200, bluePaint);
canvas.drawLine(50, 220, 250, 220, redPaint);

// Draw text
canvas.drawText("Canvas & Paint Demo", getWidth() / 2, 280, textPaint);

// Draw custom path
canvas.drawPath(customPath, redPaint);
canvas.drawPath(customPath, bluePaint);

// Draw rounded rectangle
RectF roundRect = new RectF(350, 300, 550, 400);
canvas.drawRoundRect(roundRect, 20, 20, greenPaint);

// Draw arc
RectF arcRect = new RectF(50, 500, 200, 650);
canvas.drawArc(arcRect, 0, 270, true, bluePaint);
}
}

Main Activity

package com.example.canvaspaintdemo;

import android.app.Activity;
import android.os.Bundle;

public class MainActivity extends Activity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

// Set the custom view as content
CustomDrawingView customView = new CustomDrawingView(this);
setContentView(customView);
}
}

Advanced Paint Features

Gradient Effects

// Linear gradient
LinearGradient linearGradient = new LinearGradient(
0, 0, 200, 200,
Color.RED, Color.BLUE,
Shader.TileMode.CLAMP
);
paint.setShader(linearGradient);

// Radial gradient
RadialGradient radialGradient = new RadialGradient(
100, 100, 50,
Color.YELLOW, Color.RED,
Shader.TileMode.CLAMP
);
paint.setShader(radialGradient);

Text Effects

// Shadow effect
paint.setShadowLayer(5, 3, 3, Color.GRAY);

// Underline text
paint.setUnderlineText(true);

// Strike through text
paint.setStrikeThruText(true);

Answer B: Private Preferences in Android

Understanding Private Preferences

Private Preferences in Android are application-specific key-value storage mechanisms that are accessible only to your application.

Key Characteristics:

  • Privacy: Data is private to your application
  • Persistence: Data survives application restarts
  • Lightweight: Suitable for small amounts of data
  • Type Safety: Supports various data types

Creating and Working with Private Preferences

Basic Implementation

package com.example.privatepreferences;

import android.app.Activity;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

public class PreferencesActivity extends Activity {
private static final String PREFS_NAME = "MyAppPreferences";
private static final String KEY_USERNAME = "username";
private static final String KEY_EMAIL = "email";
private static final String KEY_AGE = "age";
private static final String KEY_IS_LOGGED_IN = "is_logged_in";

private SharedPreferences sharedPreferences;
private SharedPreferences.Editor editor;

private EditText etUsername, etEmail, etAge;
private TextView tvDisplayInfo;
private Button btnSave, btnLoad, btnClear;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_preferences);

initViews();
initPreferences();
setupClickListeners();
loadSavedData();
}

private void initViews() {
etUsername = findViewById(R.id.etUsername);
etEmail = findViewById(R.id.etEmail);
etAge = findViewById(R.id.etAge);
tvDisplayInfo = findViewById(R.id.tvDisplayInfo);
btnSave = findViewById(R.id.btnSave);
btnLoad = findViewById(R.id.btnLoad);
btnClear = findViewById(R.id.btnClear);
}

private void initPreferences() {
// Initialize SharedPreferences in private mode
sharedPreferences = getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE);
editor = sharedPreferences.edit();
}

private void setupClickListeners() {
btnSave.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
saveUserData();
}
});

btnLoad.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
loadSavedData();
}
});

btnClear.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
clearAllData();
}
});
}

private void saveUserData() {
String username = etUsername.getText().toString().trim();
String email = etEmail.getText().toString().trim();
String ageStr = etAge.getText().toString().trim();

if (username.isEmpty() || email.isEmpty() || ageStr.isEmpty()) {
Toast.makeText(this, "Please fill all fields", Toast.LENGTH_SHORT).show();
return;
}

try {
int age = Integer.parseInt(ageStr);

// Save data to SharedPreferences
editor.putString(KEY_USERNAME, username);
editor.putString(KEY_EMAIL, email);
editor.putInt(KEY_AGE, age);
editor.putBoolean(KEY_IS_LOGGED_IN, true);
editor.putLong("last_login", System.currentTimeMillis());

// Commit changes
editor.apply(); // or editor.commit()

Toast.makeText(this, "Data saved successfully!", Toast.LENGTH_SHORT).show();
displaySavedData();

} catch (NumberFormatException e) {
Toast.makeText(this, "Please enter a valid age", Toast.LENGTH_SHORT).show();
}
}

private void loadSavedData() {
// Retrieve data with default values
String username = sharedPreferences.getString(KEY_USERNAME, "");
String email = sharedPreferences.getString(KEY_EMAIL, "");
int age = sharedPreferences.getInt(KEY_AGE, 0);
boolean isLoggedIn = sharedPreferences.getBoolean(KEY_IS_LOGGED_IN, false);
long lastLogin = sharedPreferences.getLong("last_login", 0);

// Update UI with loaded data
etUsername.setText(username);
etEmail.setText(email);
etAge.setText(age > 0 ? String.valueOf(age) : "");

displaySavedData();

if (!username.isEmpty()) {
Toast.makeText(this, "Data loaded successfully!", Toast.LENGTH_SHORT).show();
}
}

private void displaySavedData() {
String username = sharedPreferences.getString(KEY_USERNAME, "Not set");
String email = sharedPreferences.getString(KEY_EMAIL, "Not set");
int age = sharedPreferences.getInt(KEY_AGE, 0);
boolean isLoggedIn = sharedPreferences.getBoolean(KEY_IS_LOGGED_IN, false);

String displayText = "Saved Information:\n\n" +
"Username: " + username + "\n" +
"Email: " + email + "\n" +
"Age: " + (age > 0 ? age : "Not set") + "\n" +
"Logged In: " + (isLoggedIn ? "Yes" : "No");

tvDisplayInfo.setText(displayText);
}

private void clearAllData() {
editor.clear();
editor.apply();

// Clear input fields
etUsername.setText("");
etEmail.setText("");
etAge.setText("");

displaySavedData();
Toast.makeText(this, "All data cleared!", Toast.LENGTH_SHORT).show();
}

// Additional utility methods
private void removeSpecificKey(String key) {
editor.remove(key);
editor.apply();
}

private boolean containsKey(String key) {
return sharedPreferences.contains(key);
}

private void getAllPreferences() {
Map<String, ?> allPrefs = sharedPreferences.getAll();
for (Map.Entry<String, ?> entry : allPrefs.entrySet()) {
String key = entry.getKey();
Object value = entry.getValue();
// Process each preference
}
}
}

XML Layout (activity_preferences.xml)

<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp">

<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Private Preferences Demo"
android:textSize="24sp"
android:textStyle="bold"
android:layout_gravity="center"
android:layout_marginBottom="24dp" />

<EditText
android:id="@+id/etUsername"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Enter username"
android:layout_marginBottom="12dp" />

<EditText
android:id="@+id/etEmail"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Enter email"
android:inputType="textEmailAddress"
android:layout_marginBottom="12dp" />

<EditText
android:id="@+id/etAge"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Enter age"
android:inputType="number"
android:layout_marginBottom="24dp" />

<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">

<Button
android:id="@+id/btnSave"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Save"
android:layout_marginEnd="4dp" />

<Button
android:id="@+id/btnLoad"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Load"
android:layout_marginStart="4dp"
android:layout_marginEnd="4dp" />

<Button
android:id="@+id/btnClear"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Clear"
android:layout_marginStart="4dp" />

</LinearLayout>

<TextView
android:id="@+id/tvDisplayInfo"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:background="#F5F5F5"
android:padding="16dp"
android:text="No data saved yet..."
android:textSize="14sp" />

</LinearLayout>

</ScrollView>

Best Practices for Private Preferences

1. Use Constants for Keys

public class PreferenceKeys {
public static final String USER_SETTINGS = "user_settings";
public static final String USERNAME = "username";
public static final String THEME_MODE = "theme_mode";
public static final String NOTIFICATIONS_ENABLED = "notifications_enabled";
}

2. Create Helper Class

public class PreferenceManager {
private SharedPreferences sharedPreferences;
private SharedPreferences.Editor editor;

public PreferenceManager(Context context) {
sharedPreferences = context.getSharedPreferences("app_prefs", Context.MODE_PRIVATE);
editor = sharedPreferences.edit();
}

public void saveString(String key, String value) {
editor.putString(key, value);
editor.apply();
}

public String getString(String key, String defaultValue) {
return sharedPreferences.getString(key, defaultValue);
}

// Add methods for other data types...
}

3. Handle Complex Data

// Storing objects as JSON
public void saveUserObject(User user) {
Gson gson = new Gson();
String userJson = gson.toJson(user);
editor.putString("user_object", userJson);
editor.apply();
}

public User getUserObject() {
String userJson = sharedPreferences.getString("user_object", null);
if (userJson != null) {
Gson gson = new Gson();
return gson.fromJson(userJson, User.class);
}
return null;
}

Summary Comparison

AspectCanvas & PaintPrivate Preferences
PurposeCustom drawing and graphicsData storage and retrieval
Use CaseUI customization, games, chartsSettings, user data, app state
ComplexityMedium to HighLow to Medium
PerformanceCan be intensiveFast and lightweight
Data TypesGraphics primitivesPrimitive data types + JSON

← Back to RETEST 2024